#include "head.h"
#define LENGTH 4096

// client download 
int send_bigfile(PathStack * stack, int socketfd, char *name){
    
    char vir_path[1024] = { 0 };
    pathPeek(stack, vir_path);
    char cur_path[1024] = { 0 };
    strncpy(cur_path, stack->init_path, 1024);
    strcat(cur_path, vir_path);
    strcat(cur_path, "/");
    strcat(cur_path, name);
    int str_len = strlen(cur_path);
    char file_name[1024] = {0};
    strncpy(file_name, cur_path+1, str_len-1);
    printf("文件路径: %s\n", file_name);
    
    int fd = open(file_name, O_RDWR);
    printf("%d\n", fd);
    ERROR_CHECK(fd, -1, "open");
    
    send(socketfd, &fd, sizeof(int), 0);
    if(fd == -1){
        printf("没有客户端要求的文件\n");
        return -1;    
    }

    //获取客户端要求下载文件的大小
    struct stat stat_file;
    fstat(fd, &stat_file);
    printf("file size: %ld\n", stat_file.st_size);
    
    //接收客户端现有文件的大小
    off_t real_size;
    recv(socketfd, &real_size, sizeof(off_t), MSG_WAITALL);
    //printf("real size: %ld\n", real_size);
    
    //判断文件是否一致，一致则直接结束
    int flag_same = 0;
    if(real_size == stat_file.st_size){
        printf("文件完全一致，不需要上传\n");
        flag_same = 1;
        send(socketfd, &flag_same, sizeof(int), MSG_NOSIGNAL);
        return 0;
    }
    send(socketfd, &flag_same, sizeof(int), MSG_NOSIGNAL);

    //position用于记录当前文件指针的位置
    //因为position要作为mmap的offset参数，所以只能是LENGTH的整数倍
    int position = (real_size/LENGTH)*LENGTH;
    //printf("position: %d\n", position);
    
    //每次传输的长度
    int length = LENGTH;
    //发送文件
    while(1){
        //如果总文件的大小和当前传输到的位置(positionon)相差的值小于一次传输的长度，就把长度改为这个差值
        if(stat_file.st_size - position < LENGTH){
            length = stat_file.st_size -position;
        }
        //从position的位置映射length的长度到file_read
        char *file_read = (char *)mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, position);
        ERROR_CHECK(file_read, MAP_FAILED, "mmap");
        //传输内容的长度
        send(socketfd, &length, sizeof(int), MSG_NOSIGNAL);
        //printf("length = %d\n", length);
        //传输的内容
        send(socketfd, file_read, length, MSG_NOSIGNAL);
        munmap(file_read, length);
        //传输一次后，更新position的值
        position += LENGTH;
        //printf("position: %d\n", position);
        //如果position的值大于等于文件的总长度，说明position已经走到了文件的末尾
        //向服务端发送一个长度，值为0，表示传输结束
        if(position >= stat_file.st_size){
            length = 0;
            send(socketfd, &length, sizeof(int), MSG_NOSIGNAL);
            printf("文件传输完毕\n");
            break;
        }
    }
    close(fd);
    return 0;
}

int recv_bigfile(PathStack *stack, int socketfd, char *name){
    char vir_path[1024] = { 0 };
    pathPeek(stack, vir_path);
    char cur_path[1024] = { 0 };
    strncpy(cur_path, stack->init_path, 1024);
    strcat(cur_path, vir_path);
    strcat(cur_path, "/");
    strcat(cur_path, name);
    int str_len = strlen(cur_path);
    char file_name[1024] = {0};
    strncpy(file_name, cur_path+1, str_len-1);
    printf("文件路径: %s\n", file_name);
    
    int fd = open(file_name, O_WRONLY | O_CREAT, 0666);
    ERROR_CHECK(fd, -1, "open");
    //printf("%d\n", fd);
    //现有文件大小
    struct stat stat_file;
    fstat(fd, &stat_file);
    printf("file size: %ld\n", stat_file.st_size);
    //将现有文件大小发给客户端
    send(socketfd, &stat_file.st_size, sizeof(off_t), MSG_NOSIGNAL);
    
    int flag_same;
    recv(socketfd, &flag_same, sizeof(int), MSG_WAITALL);
    if(flag_same == 1){
        printf("文件完全一致，不需要上传\n");
        return 0;
    }

    //获取断点
    off_t position = (stat_file.st_size/LENGTH)*LENGTH;
    printf("position: %ld\n", position);
    //改变文件指针的指向到断点
    int ret_lseek = lseek(fd, position, SEEK_SET);
    ERROR_CHECK(ret_lseek, -1, "lseek");
    //接收文件
    while(1){
        int buf_len;
        char buf[5000] = {0};
        recv(socketfd, &buf_len, sizeof(int), MSG_WAITALL);
        if(buf_len == 0){
            printf("文件下载完毕\n");
            break;
        }
        //printf("buf_len: %d\n", buf_len);
        recv(socketfd, buf, buf_len, MSG_WAITALL);
        //printf("buf: %s\n", buf);
        write(fd, buf, buf_len);
        if(buf_len == 0){
            printf("文件下载完毕\n");
            break;
        }
    }
    close(fd);
    return 0;
}
